/*
 * Basado en el libro de Duane A. Bailey, "Java Structures", pág. 191 y en la hoja de trabajo 4
 */
package Hoja6;

import java.util.Iterator;

/**
 *
 * @param <E> 
 * @author María Fernanda Martínez
 */
public class SinglyLinkedList <E> extends AbstractList<E>{
    /**
     * Tamaño de la lista
     */
    protected int count; 
    /**
     * Referencia al primer elemento
     */
    protected Node<E> head; 
    
    /**
     * Nombre: SinglyLinkedList
     * Descipcion: constructor de la clase
     * Pre: no hay
     * Post: nueva lista vacia
     * No hay parametro ni valor de retorno
     */
    public SinglyLinkedList()
    {
        head = null;
        count = 0;
    }
   
    /**
     * Nombre: size
     * Descripcion: obtiene la cantidad de elementos presentes en la lista
     * Pre: ninguno
     * Post: regresa la cantidad de elementos en la pila
     * Parametros: ninguno
     * @return valor tipo int
     */
    @Override
    public int size()
    {
        return count;
    }
    
    /**
     * Nombre: addFirst
     * Descripcion: agrega un objeto a la lista en la primera posicion
     * Pre: espacio disponible
     * Post: valor agregado al inicio de la lista
     * @param value de tipo E
     * Valor de retorno: ninguno
     */
    @Override
    public void addFirst(E value)
    {
        head = new Node<>(value, head);
        count++;
    }
    
    /**
     * Nombre: clear
     * Descripcion: borra todos los elementos de la lista
     * Pre: ninguno
     * Post: lista vacia
     * Parametros: ninguno
     * Valor de retorno: ninguno
     */
    @Override
    public void clear(){
        count=0;
        head=null;
    }

    /**
     * Nombre: getFirst
     * Descripcion: obtiene el ultimo valor que se inserto en la lista
     * Pre: hay valor en la lista
     * Post: muestra valor al inicio de la lista
     * Parametros: ninguno
     * @return valor tipo E
     */
    @Override
    public E getFirst() {
        return head.value();
    }

    /**
     * Nombre: removeFirst
     * Descripcion: el objeto que entro de ultimo a la lista es retirado de ella
     * Pre: hay valor en la lista
     * Post: valor removido de la lista
     * Parametros: ninguno
     * @return valor tipo E
     */
    @Override
    public E removeFirst() {
        
        Node<E> temp = head;
        head = head.next();
        count--;
        return temp.value();
    }
    
    /**
     * Nombre: removeLast
     * Descripción: retira el último elemento de la lista
     * Pre: lista no está vacía
     * Post: último elemento de la lista retirado
     * No hay parámetros
     * @return
     */
    public E removeLast()
    {
        Node<E> finger = head;
        Node<E> previous = null;
        while (finger.next() != null) // encontrar final de la lista
        {
            previous = finger;
            finger = finger.next();
        }
        // finger es null, o apunta al final de la lista
        if (previous == null)
        {
            // tiene un solo elemento
            head = null;
        }
        else
        {
            // apuntar a último elemento es reseteado
            previous.setNext(null);
        }
        count--;
        return finger.value();
    }
    
    /**
     * Nombre: remove
     * Descripción: remover un elemento con valor value
     * Pre: value no es null
     * Post: elemento con valor value removido, si no existe regresa null
     * @param value
     * @return
     */
    public E remove(E value)
    {
        Node<E> finger = head;
        Node<E> previous = null;
        while (finger != null && !finger.value().equals(value))
        {
            previous = finger;
            finger = finger.next();
        }
        // finger apunta al objetivo
        if (finger != null) {
            // se encontró elemento a remover
            if (previous == null) // es el primero
            {
                head = finger.next();
            } else { // no es el primero
                previous.setNext(finger.next());
            }
            count--;
            return finger.value();
        }
        // no se encontró, regresar null
        return null;
    }
    
    /**
     * Nombre: iterator
     * Descripción: iterador de List
     * Pre: no hay
     * Post: regresa un iterador que permite viajar a traves de una lista
     * No tiene parámetros
     * @return
     */
    public Iterator<E> iterator(){
        Iterator<E> iterator = new SinglyLinkedListIterator<>(head);
        return iterator;            
    }
              

    
}
